package cn.getech.data.metadata.service.impl;

import cn.getech.data.development.entity.ConfConnect;
import cn.getech.data.development.service.ConfConnectService;
import cn.getech.data.development.utils.DataPermissionUtil;
import cn.getech.data.development.utils.SecurityUtil;
import cn.getech.data.intelligence.common.utils.PageUtils;
import cn.getech.data.intelligence.common.utils.R;
import cn.getech.data.metadata.constant.ConnectTypeEnum;
import cn.getech.data.metadata.constant.MetaTableTypeEnum;
import cn.getech.data.metadata.constant.YesOrNoEnum;
import cn.getech.data.metadata.db.DataView;
import cn.getech.data.metadata.entity.meta.CollectionTableField;
import cn.getech.data.metadata.entity.meta.CollectionTableInfo;
import cn.getech.data.metadata.entity.permission.TreeData;
import cn.getech.data.metadata.mapper.CollectionTableFieldMapper;
import cn.getech.data.metadata.mapper.CollectionTableMapper;
import cn.getech.data.metadata.model.req.collectiontableinfo.CollectiionTableInfoListReq;
import cn.getech.data.metadata.service.CollectionTableService;
import cn.getech.system.center.utils.ShiroUtils;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.google.common.collect.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service("collectionTablePreServiceImpl")
public class CollectionTablePreServiceImpl implements CollectionTableService {

    private Logger log = LoggerFactory.getLogger(CollectionTablePreServiceImpl.class);
    @Autowired
    private SecurityUtil securityUtil;
    @Autowired
    private CollectionTableMapper collectionTableMapper;

    @Autowired
    private CollectionTableFieldMapper collectionTableFieldMapper;

    @Autowired
    private ConfConnectService confConnectService;
    private List<DataView> dbDataViewList;

    @Autowired
    public void setDbDataViewList(List<DataView> dbDataViewList) {
        this.dbDataViewList = dbDataViewList;
    }

    private DataView getDataView(Integer type) {
        for (DataView dataView : dbDataViewList) {
            if(dataView.support(type)){
                return dataView;
            }
        }
        return null;
    }

    private static void getParents(Map<Integer, TreeData> moduleMap,
                                   Integer id, List<TreeData> parents) {
        if (moduleMap.get(id) != null) {
            Integer parentId = moduleMap.get(id).getParentId();
            if (parentId != null && parentId > 0 && parents.size()<10) {
                parents.add(moduleMap.get(id));
                getParents(moduleMap, parentId, parents);
            } else {
                parents.add(moduleMap.get(id));
            }
        }
    }
    @Override
    public R dataPreview(CollectiionTableInfoListReq req) {
        Long userId= ShiroUtils.getUserId();
        if (req.getId() == null) {
            return R.error("id 不能为空");
        }
        CollectionTableInfo table = collectionTableMapper.selectById(req.getId());
        QueryWrapper<CollectionTableField> param = new QueryWrapper<CollectionTableField>()
                .eq("table_id", req.getId())
                .eq("delete_flag", YesOrNoEnum.NO.getValue())
                .orderByAsc("field_order");
        //查询资产目录负责人
        Integer id = collectionTableFieldMapper.selectUserByTableId(req.getId());
        List<TreeData> list = collectionTableFieldMapper.listDataAssetsCategory();
        Map<Integer, TreeData> treeMap=new HashMap<>();
        for (TreeData treeData : list) {
            treeMap.put(treeData.getId(),treeData);
        }
        List<TreeData> parents=new ArrayList<>();
        getParents(treeMap, id, parents);
        List<Long> userList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(parents)) {
            for (TreeData parent : parents) {
                if (StringUtils.isNotEmpty(parent.getUserIds())) {
                    for (String uid : parent.getUserIds().split(";")) {
                        userList.add(Long.parseLong(uid));
                    }
                }
            }
        }
        if (!DataPermissionUtil.isAdmin(userId.intValue()) && !userList.contains(userId)) {
            List<Integer> ids = collectionTableFieldMapper.selectHavePermissionFields(userId);
            if (CollectionUtils.isEmpty(ids)) {
                ids.add(-1);
            }
            param.in("id", ids);
        }
        List<CollectionTableField> fieldList = collectionTableFieldMapper.selectList(param);
        if (CollectionUtils.isEmpty(fieldList)) {
            return R.error("无当前表的字段权限,无法预览数据");
        }
        if (table.getSourceId() != null
                && MetaTableTypeEnum.OUT_TABLE.getValue().equals(table.getTableType())) {
            ConfConnect con = confConnectService.getById(table.getSourceId());
            if (con == null) {
                return R.error("暂时不支持表[%s]的数据预览,此表无数据源信息", table.getTableName());
            }
            DataView dataView = getDataView(con.getTypeId());
            if (dataView == null) {
                return R.error("暂时不支持表[%s]的数据预览", table.getTableName());
            }
            //hive查询结果的分页
            List<String> columnList = fieldList.stream().map(CollectionTableField::getFieldName).collect(Collectors.toList());
            List<JSONObject> data = Lists.newArrayList();
            Connection dbCon = null;
            Statement prepareStatement = null;
            ResultSet result = null;
            try {
                dbCon = getDbConnection(con, table.getDbName());
                if (ConnectTypeEnum.Oracle.getCode().equals(con.getTypeId())) {
                    table.setDbName(con.getUsername().toUpperCase());
                }
                String countSql = dataView.getCountSql(table);
                long totalCount = 100000;
                prepareStatement = dbCon.createStatement();
                if (StringUtils.isNotEmpty(countSql)) {
                    log.info("countSql:\n{}",countSql);
                    result = prepareStatement.executeQuery(countSql);
                    while (result.next()) {
                        totalCount = result.getLong("totalCount");
                    }
                }
                if (totalCount > 0) {
                    String sql = dataView.getSql(table, columnList, req.getPage(), req.getLimit());
                    log.info("sql:\n{}", sql);
                    result = prepareStatement.executeQuery(sql);
                    ResultSetMetaData resultSetMetaData = result.getMetaData();
                    while (result.next()) {
                        JSONObject object = new JSONObject();
                        for (int i = 1; i < resultSetMetaData.getColumnCount() + 1; i++) {
                            String titleName = resultSetMetaData.
                                    getColumnName(i).replaceAll(String.format("%s.", table.getTableName()), "");
                            for (String c : columnList) {
                                if (c.equalsIgnoreCase(titleName)) {
                                    if (result.getObject(i) != null) {
                                        object.put(c, result.getObject(i).toString());
                                    }else{
                                        object.put(c, "");
                                    }
                                    break;
                                }
                            }
                        }
                        data.add(object);
                    }
                }
                log.info("data:{}",JSONObject.toJSONString(data));
                PageUtils pageData = new PageUtils<>(data, totalCount, req.getLimit(), req.getPage());
                R r = R.okWithPage(pageData);
                r.put("titleList", columnList);
                collectionTableMapper.updateHotCount(req.getId());
                return r;
            } catch (Exception e) {
                log.error("数据获取失败",e);
                return R.error("表[%s]的数据预览错误，详情%s", table.getTableName(),e.getMessage());
            }finally {
                try {
                    if (result != null) {
                        result.close();
                    }
                    if (prepareStatement != null) {
                        prepareStatement.close();
                    }
                    if (dbCon != null) {
                        dbCon.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }else{
            return R.error("当前表无数据源,或不是外部元数据,无法预览数据");
        }
    }

    private Connection getDbConnection(ConfConnect con, String dbName) throws Exception {
        con.setPassword(securityUtil.decrypt(con.getPassword()));
        ConnectTypeEnum driver = ConnectTypeEnum.getDriver(con.getTypeId());
        String driverClass = driver.getDriverClass();
        String serverUrl = String.format(driver.getUrl(),
                con.getHost(), con.getPort(), dbName);
        Class.forName(driverClass);
        DriverManager.setLoginTimeout(50);
        return DriverManager.getConnection(
                serverUrl, con.getUsername(), con.getPassword());
    }

}
